#!/usr/bin/python
# Copyright (c) 2006 Intel Corporation
# All rights reserved.
#
# This file is distributed under the terms in the attached INTEL-LICENSE     
# file. If you do not find these files, copies can be found by writing to
# Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
# 94704.  Attention:  Intel License Inquiry.

from xml.dom import *
from xml.dom.minidom import *
from re import match
from sys import *

sector_size = 256
flash_size = 2048 # in sectors

volumes = {}
volmap = []

# print an error message and exit
def nfail(s):
  stderr.write(s + "\n")
  exit(2)

def check_volume(name, base, size):
  if base == "":
    base = None
  else:
    try:
      base = int(base)
    except ValueError:
      nfail("invalid base for volume %s" % name)
    if (base & (sector_size - 1)) != 0:
      nfail("base of volume %s is not a multiple of %d" % (name, sector_size))
    base /= sector_size

  try:
    size = int(size)
  except ValueError:
    nfail("invalid size for volume %s" % name)
  if (size & (sector_size - 1)) != 0:
    nfail("size of volume %s is not a multiple of %d" % (name, sector_size))
  size /= sector_size

  name = name.upper()
  if volumes.has_key(name):
    nfail("duplicate definition of volume %s" % name)
  if not match("^[a-zA-Z0-9_]+$", name):
    nfail("invalid volume name %s" % name)
  volumes[name] = (base, size)

def allocate_at(name, base, size):
  # check for overlap of existing allocations
  for (vname, vbase, vsize) in volmap:
    if base in range(vbase, vbase + vsize) or base + size - 1 in range(vbase, vbase + vsize) or vbase in range(base, base + size) or vbase + vsize - 1 in range(base, base + size):
      nfail("volume %s overlaps volume %s" % (name, vname))

  # insert at correct position
  for i in range(len(volmap)):
    if base < volmap[i][1]:
      volmap.insert(i, (name, base, size))
      return

  # it's the last volume...
  volmap.append((name, base, size))

def allocate(name, size):
  # We just do first fit. We could spend endless effort doing better.
  base = 0
  for i in range(len(volmap)):
    (vname, vbase, vsize) = volmap[i]
    if base < vbase and size <= vbase - base:
      volmap.insert(i, (name, base, size))
      return
    base = vbase + vsize
  volmap.append((name, base, size))

try:
  dom = parse(stdin)
except xml.parsers.expat.ExpatError:
  nfail("no valid input")

for volume in dom.documentElement.getElementsByTagName("volume"):
  name = volume.getAttribute("name")
  size = volume.getAttribute("size")
  base = volume.getAttribute("base")
  if name == None:
    nfail("name omitted in volume")
  if size == None:
    nfail("size omitted in volume %s" % name)
  check_volume(name, base, size)

# allocate fixed-address volumes
for name in volumes.keys():
  (base, size) = volumes[name]
  if base != None:
    allocate_at(name, base, size)

# allocate movable volumes
for name in volumes.keys():
  (base, size) = volumes[name]
  if base == None:
    allocate(name, size)

if len(volmap) == 0:
  nfail("no volumes")

(lastname, lastbase, lastsize) = volmap[len(volmap) - 1]
if lastbase + lastsize > flash_size:
  nfail("out of space (using %d bytes, have only %d)" %
        ((lastbase + lastsize) * sector_size, flash_size * sector_size))

# print some code
print "#ifndef STORAGE_VOLUMES_H"
print "#define STORAGE_VOLUMES_H"
print
print "enum {"
for (vname, vbase, vsize) in volmap:
  print "  VOLUME_%s, " % vname
print "};"
print
print "#endif"

print "#if defined(VS)"
for (vname, vbase, vsize) in volmap:
  print "VS(VOLUME_%s, %d)" % (vname, vsize)
print "#undef VS"
print "#endif"

print "#if defined(VB)"
for (vname, vbase, vsize) in volmap:
  print "VB(VOLUME_%s, %d)" % (vname, vbase)
print "#undef VB"
print "#endif"

